package org.yscz.media;

import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.ListenableFutureCallback;
import org.springframework.web.client.AsyncRestTemplate;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import org.yscz.common.ViewConfig;
import org.yscz.entity.RoomBean;

/**
 * 流媒体业务
 */
@Service
public class MediaService {
    private static Logger logger = LoggerFactory.getLogger(MediaService.class);

    @Value("${yscz.mediaServer.ip}")
    private String mediaServerIp;

    @Value("${yscz.mediaServer.rtsp-port}")
    private String mediaServerRtspPort;

    @Value("${yscz.mediaServer.rtmp-port}")
    private String mediaServerRtmpPort;

    @Value("${yscz.mediaServer.http-port}")
    private String mediaServerHttpPort;

    @Value("${yscz.usbDevice.enable:true}")
    private boolean usbEnable;

    @Value("${yscz.usbDevice.videoName:0}")
    private String usbVideoName;

    @Value("${yscz.usbDevice.videoSize:640x480}")
    private String usbVideoSize;

    @Value("${yscz.usbDevice.audioName}")
    private String usbAudioName;

    @Value("${yscz.pictures.upload.location}")
    private String location;

    /**
     * 功能：结束 USB 音视频推流
     * 范例：http://192.168.16.155:8080/stopUsbStream
     * 返回：
     * {
     * "status" : 0,
     * "msg" : start push usb stream
     * }
     *
     * @return
     */
    public int stopUsbStream() {
        try {
            String httpUrl = "http://" + mediaServerIp + ":" + mediaServerHttpPort + "/stopUsbStream";
            logger.info("stop to push usb stream url:[{}]", httpUrl);
            RestTemplate client = new RestTemplate();
            String result = client.getForEntity(httpUrl, String.class).getBody();
            logger.info("stop usb stream result：[{}]", result);
            if (result != null && JSON.parseObject(result).getIntValue("status") == 0) {
                return 0;
            }
        } catch (RestClientException e) {
            logger.info("push usb stream error e：" + e);
        }
        return -1;
    }

    /**
     * 功能：USB 音视频推流
     * 范例：http://192.168.16.155:8080/pushUsbStream?video=0&size=640x480&audio=麦克风 (Realtek USB Audio)&dst=rtsp://192.168.16.122:8554/live/999
     * 参数：
     * video(必选)：视频
     * size(非必选)：视频尺寸
     * audio(必选)：音频
     * dst  (必选)：流地址
     * 返回：
     * {
     * "status" : 0,
     * "msg" : start push usb stream
     * }
     *
     * @return
     */
    public int pushUsbStream(RoomBean roomBean) {
        try {
            String streamUrl = "rtsp://" + mediaServerIp + ":" + mediaServerRtspPort + "/live/" + roomBean.getUuid();
            String httpUrl = "http://" + mediaServerIp + ":" + mediaServerHttpPort + "/" +
                    "pushUsbStream?video=" + usbVideoName + "&size=" + usbVideoSize + "&audio=" + usbAudioName + "&dst=" + streamUrl;
            logger.info("begin to push usb stream url:[{}]", httpUrl);
            RestTemplate client = new RestTemplate();
            String result = client.getForEntity(httpUrl, String.class).getBody();
            logger.info("push usb stream finish result:[{}]", result);
            if (result != null && JSON.parseObject(result).getIntValue("status") == 0) {
                roomBean.setCameraUrl(streamUrl);
                return 0;
            }
        } catch (RestClientException e) {
            logger.info("push usb stream error e：" + e);
        }
        return -1;
    }


    /**
     * addStreamProxy
     * 功能： 添加rtsp/rtmp拉流代理
     * 范例： http://192.168.100.245:8080/addStreamProxy?vhost=__defaultVhost__&app=live&stream=43&enable_rtsp=1&enable_rtmp=1&url=rtsp://admin:admin@192.168.16.111:554
     * 参数
     * vhost (必选)：添加的流的虚拟主机，默认__defaultVhost__
     * app（必选）：添加的流的应用名，例如live
     * stream（必选）：添加的流的id名，例如test
     * url （必选）： 拉流地址
     * enable_rtsp（必选）：是否转rtsp
     * enable_rtmp （必选）：是否转rtmp
     * enable_hls (可选)：是否转hls
     * enable_mp4（可选）：是否mp4录制
     * rtp_type（可选）：rtsp拉流时，拉流方式，0：tcp，1：udp，2：组播
     * retry_count （可选）: 拉流失败重试次数，-1表示无数次
     * 返回
     * {
     * "code" : 0,
     * "data" : {
     * "key" : "__defaultVhost__/live/1"
     * }
     * }
     *
     * @return
     */
    public void addStream(RoomBean roomBean) {
        try {
            String addStreamUrl = "http://" + mediaServerIp + ":" + mediaServerHttpPort + "/" +
                    "addStreamProxy?vhost=__defaultVhost__&app=live&stream=" + roomBean.getUuid() + "&enable_rtsp=1&enable_rtmp=1&retry_count=0&url=" + roomBean.getCameraUrl();
            logger.info("MediaService.addStream addStreamUrl ：" + addStreamUrl);
            AsyncRestTemplate restTemplate = new AsyncRestTemplate();
            ListenableFuture<ResponseEntity<String>> future = restTemplate.getForEntity(addStreamUrl, String.class);
            future.addCallback(new ListenableFutureCallback<ResponseEntity<String>>() {
                @Override
                public void onFailure(Throwable ex) {
                    logger.error("流媒体调用失败:[{}]", ex.getMessage());
                    // 关闭USB推流
                    if (usbEnable) {
                        logger.info("使用USB设备，关闭USB推流结果:[{}]", stopUsbStream());
                    }
                }

                @Override
                public void onSuccess(ResponseEntity<String> result) {

                }
            });
        } catch (RestClientException e) {
            logger.error("流媒体调用失败:[{}]", e.getMessage());
        }
    }

    /**
     * 功能：开始录制hls或MP4
     * 范例：http://192.168.16.155:8080/startRecord?type=1&vhost=defaultVhost&app=live&stream=15&wait_for_record=0&continue_record=1&customized_path=/home
     * 参数：
     * type(必选)：0为hls，1为mp4
     * vhost (必选)：添加的流的虚拟主机，默认__defaultVhost__
     * app（必选）：添加的流的应用名，例如live
     * stream（必选）：添加的流的id名，例如test
     * wait_for_record（必选）：1代表等待流注册后再录制，置0在流未注册时返回失败
     * continue_record（必选）：1代表流注销时继续等待录制，0代表流注销时立即停止录制。
     * record_path（可选）：录像保存地址，不填则是默认地址，暂时不支持hls格式
     * 返回：
     * {
     * "code" : 0,
     * "result" : 0 # 0代表成功，负数代表失败及原因
     * }
     *
     * @param streamId
     * @param recPath
     * @return
     */
    public int startRecord(String streamId, String recPath) throws RestClientException {
        try {
            String streamUrl = "rtmp://" + mediaServerIp + ":" + mediaServerRtmpPort + "/live/" + streamId;
            String startRecordUrl = "http://" + mediaServerIp + ":" + mediaServerHttpPort + "/" +
                    "startFfmpegRecord?src=" + streamUrl + "&record_path=" + recPath;
            logger.info("begin to start record " + startRecordUrl);
            RestTemplate client = new RestTemplate();
            String startRecord = client.getForEntity(startRecordUrl, String.class).getBody();
            logger.info("MediaService.startRecord result：" + startRecord);
            return 0;
        } catch (RestClientException e) {
            logger.info("MediaService.startRecord err e：" + e.getMessage());
            throw new RestClientException("MediaService.startRecord 调用接口报错", e);
        }
    }


    /**
     * 向媒体服务器发送停止录制命令
     * 功能：停止录制流
     * <p>
     * 范例：http://192.168.16.155:8080/stopRecord?type=1&vhost=defaultVhost&app=live&stream=15
     * <p>
     * 参数：
     * <p>
     * type(必选)：0为hls，1为mp4
     * vhost (必选)：添加的流的虚拟主机，默认__defaultVhost__
     * app（必选）：添加的流的应用名，例如live
     * stream（必选）：添加的流的id名，例如test
     * 返回：
     * <p>
     * {
     * "code" : 0,
     * "result" : 1 # 1:停止录制成功，0:失败，原因是不存在该录制行为
     * }
     *
     * @param videoRecFile
     * @return
     */
    public int stopRecord(String videoRecFile) throws RestClientException {
        try {
            logger.info("begin to stop record for  " + videoRecFile);
            String url = "http://" + mediaServerIp + ":" + mediaServerHttpPort +
                    "/stopFfmpegRecord?record_path=" + videoRecFile;
            logger.info("begin to stop record " + url);
            RestTemplate client = new RestTemplate();
            String stopRecord = client.getForEntity(url, String.class).getBody();
            logger.info("MediaService.stopRecord result：" + stopRecord);
            return Integer.parseInt(stopRecord);
        } catch (RestClientException e) {
            logger.error("MediaService.stopRecord err e：" + e.getMessage());
            throw new RestClientException("MediaService.stopRecord 调用接口报错", e);
        }
    }

    public String getFfmpegRecordList() throws RestClientException {
        try {
            String url = "http://" + mediaServerIp + ":" + mediaServerHttpPort + "/" +
                    "/getFfmpegRecordList";
            logger.info("MediaService.getFfmpegRecordList url: " + url);
            RestTemplate client = new RestTemplate();
            String fmpegRecordList = client.getForEntity(url, String.class).getBody();
            logger.info("MediaService.getFfmpegRecordList result：" + fmpegRecordList);
            return fmpegRecordList;
        } catch (RestClientException e) {
            logger.error("MediaService.getFfmpegRecordList err e：" + e.getMessage());
            throw new RestClientException("MediaService.getFfmpegRecordList 调用接口报错", e);
        }
    }

    /**
     * delStreamProxy
     * <p>
     * 功能： 删除rtsp/rtmp拉流代理
     * <p>
     * 参数： key(必选)： addStreamProxy接口返回的key
     * <p>
     * 范例： http://192.168.100.245:8080/delStreamProxy?key=defaultVhost/live/1
     * <p>
     * 返回：
     * <p>
     * {
     * "code" : 0,
     * "data" : {
     * "flag" : true
     * }
     * }
     *
     * @param streamId
     * @return
     */
    public int delSteam(String streamId) throws RestClientException {
        try {
            String addStreamUrl = "http://" + mediaServerIp + ":" + mediaServerHttpPort + "/" +
                    "delStreamProxy?key=__defaultVhost__/live/" + streamId;
            logger.info("delete stream url ：" + addStreamUrl);
            RestTemplate client = new RestTemplate();
            String addStream = client.getForEntity(addStreamUrl, String.class).getBody();
            //logger.info("MediaService.delSteam result：" + addStream);
            ViewConfig.mediaStartCacheUuid = null;
            return 0;
        } catch (RestClientException e) {
            logger.error("MediaService.delSteam err  e：" + e.getMessage());
            throw new RestClientException("MediaService.delSteam 调用接口报错", e);
        }
    }

    /**
     * 功能获取一帧图像
     * 范例：http://192.168.100.245:8080/getImage?src=rtsp://admin:1234qwer@192.168.16.202
     * 参数：
     * src (必选) ： 需要获取截图的视频流的url
     *
     * @param roomId
     * @return
     */
    public String getImage(String roomId) {
        String streamUrl = "rtsp://" + mediaServerIp + ":" + mediaServerRtspPort + "/live/" + roomId;
        return "http://" + mediaServerIp + ":" + mediaServerHttpPort + "/getImage?src=" + streamUrl;
    }

    public String saveImage(String roomId) {
        String streamUrl = "rtsp://" + mediaServerIp + ":" + mediaServerRtspPort + "/live/" + roomId;
        return "http://" + mediaServerIp + ":" + mediaServerHttpPort + "/saveImage?src=" + streamUrl + "&image_path=" + location + roomId + ".jpg";
    }


    /**
     * 截取视频
     * 范例：http://192.168.100.245:8080/clipVideo?src_video=q.mp4&dst_video=2.mp4&start_time=0:1:30&end_time=0:2:30
     * * 参数：src_video:原始视频路径包含文件名
     * dst_video:截取后视频存放路径包含文件名
     * start_time:开始截取时间
     * end_time:截取至时间
     * * src (必选) ： 需要获取截图的视频流的url
     *
     * @param videoPathName
     * @param alarmVideo
     * @param startDate
     * @param stopDate
     * @return
     */
    public int clipVideo(String videoPathName, String alarmVideo, String startDate, String stopDate) {
        try {
            String clipVideoUrl = "http://" + mediaServerIp + ":" + mediaServerHttpPort + "/" +
                    "clipVideo?src_video=" + videoPathName + "&dst_video=" + alarmVideo + "&start_time=" + startDate + "&end_time=" + stopDate;
            logger.info("MediaService.clipVideo cut alarm video url ：" + clipVideoUrl);
            RestTemplate client = new RestTemplate();
            String clipResult = client.getForEntity(clipVideoUrl, String.class).getBody();
            logger.info("MediaService.clipVideo result：" + clipResult);
            return 0;
        } catch (RestClientException e) {
            logger.error("MediaService.cutAlarmVideo err  e：" + e.getMessage());
            throw new RestClientException("MediaService.clipVideo 调用接口报错", e);
        }
    }

    /**
     * 通知流媒体保存告警图片
     *
     * @param uid
     * @param imagePath
     */
    public void saveCacheImage(String uid, String imagePath) {
        try {
            logger.info("MediaService.saveCacheImage uid：" + uid + ", imagePath:" + imagePath);
            String saveCacheImageUrl = "http://" + mediaServerIp + ":" + mediaServerHttpPort + "/saveCacheImage?uid=" + uid + "&image_path=" + imagePath;
            logger.info("save cache image url ：" + saveCacheImageUrl);
            RestTemplate client = new RestTemplate();
            String saveResult = client.getForEntity(saveCacheImageUrl, String.class).getBody();
            logger.info("MediaService.saveAlarmImages saveResult：" + saveResult);
        } catch (Exception e) {
            logger.error("MediaService.saveAlarmImages err  e：" + e.getMessage());
            throw new RestClientException("MediaService.saveAlarmImages 调用接口报错", e);
        }
    }

    /*public void getSoundIntensity(RoomBean roomBean) throws Exception {

        WebSocketClient webSocketClient = null;
        try {
            String urlPath="ws://"+websocketIp+":"+websocketPort+"/getIntensity?url="+roomBean.getUrl();
            webSocketClient = new WebSocketClient(new URI(urlPath),new Draft_6455()) {
                @Override
                public void onOpen(ServerHandshake serverHandshake) {
                    logger.info("声强websocket 连接成功");
                }

                @Override
                public void onMessage(String msg) {
                    logger.info("声强websocket 收到消息 msg: "+msg);
                    Map soundMap = JSONObject.parseObject(msg);
//                    ViewConfig.soundIntensityMap.put(roomBean.getRoomId(),soundMap);

                }

                @Override
                public void onClose(int i, String s, boolean b) {
                    roomBean.setWebsocketStatus(false);
                    logger.info("声强websocket 链接已关闭");
                }

                @Override
                public void onError(Exception e) {
                    roomBean.setWebsocketStatus(false);
                    logger.error("声强websocket 发生错误已关闭 e: "+e.getMessage());
                }
            };
        } catch (Exception e) {
            logger.error("声强websocket 发生错误已关闭 e: "+e.getMessage());
            throw e;
        }
        webSocketClient.connect();
        roomBean.setWebsocketStatus(true);
        while (roomBean.isWebsocketStatus()){
            Thread.sleep(100);
            webSocketClient.getReadyState();
        }
        logger.info("声强websocket 链接状态 "+webSocketClient.getReadyState());
        logger.info("声强websocket 链接已关闭");
        if(!roomBean.isWebsocketStatus()){
            getSoundIntensity(roomBean);
        }

    }*/


}
